package main

import (
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"runtime"
	"runtime/pprof"
	"sync"
	"time"
)

var wg sync.WaitGroup

// 模拟长时间运行的任务
func longRunningTask(id int) {
	defer wg.Done()
	log.Printf("Goroutine %d 开始执行", id)

	// 模拟工作
	time.Sleep(time.Duration(id) * time.Second)

	log.Printf("Goroutine %d 执行完成", id)
}

// 模拟阻塞的Goroutine
func blockedTask(id int) {
	defer wg.Done()
	log.Printf("阻塞Goroutine %d 开始执行", id)

	// 创建一个通道，但不发送数据，导致Goroutine阻塞
	ch := make(chan int)
	<-ch // 这里会永久阻塞

	log.Printf("阻塞Goroutine %d 执行完成", id) // 这行代码永远不会执行
}

// 模拟繁忙等待的Goroutine
func busyWaitTask(id int) {
	defer wg.Done()
	log.Printf("繁忙等待Goroutine %d 开始执行", id)

	// 繁忙等待
	endTime := time.Now().Add(2 * time.Second)
	for time.Now().Before(endTime) {
		// 空循环，消耗CPU
	}

	log.Printf("繁忙等待Goroutine %d 执行完成", id)
}

func main() {
	// 启动HTTP服务器，暴露pprof端点
	go func() {
		log.Println(http.ListenAndServe("0.0.0.0:7890", nil))
	}()

	log.Println("Goroutine分析示例启动")
	log.Println("访问 http://localhost:7890/debug/pprof/goroutine 查看Goroutine信息")

	// 设置GOMAXPROCS
	runtime.GOMAXPROCS(runtime.NumCPU())

	// 创建正常运行的Goroutine
	for i := 1; i <= 5; i++ {
		wg.Add(1)
		go longRunningTask(i)
	}

	// 创建阻塞的Goroutine
	for i := 1; i <= 3; i++ {
		wg.Add(1)
		go blockedTask(i)
	}

	// 创建繁忙等待的Goroutine
	for i := 1; i <= 2; i++ {
		wg.Add(1)
		go busyWaitTask(i)
	}

	// 定期创建新的Goroutine
	go func() {
		for i := 0; i < 5; i++ {
			time.Sleep(3 * time.Second)
			wg.Add(1)
			go longRunningTask(100 + i)
			log.Printf("创建了新的Goroutine %d", 100+i)
		}
	}()

	// 等待所有非阻塞的Goroutine完成
	// 注意：阻塞的Goroutine永远不会完成，所以程序会一直运行
	log.Println("等待Goroutine完成...")

	// 创建Goroutine分析文件
	go func() {
		time.Sleep(5 * time.Second) // 等待一段时间，让Goroutine运行起来

		f, err := os.Create("goroutine.prof")
		if err != nil {
			log.Fatal("could not create goroutine profile: ", err)
		}
		defer f.Close()

		// 获取Goroutine堆栈跟踪
		if err := pprof.Lookup("goroutine").WriteTo(f, 0); err != nil {
			log.Fatal("could not write goroutine profile: ", err)
		}

		log.Println("Goroutine分析数据已写入 goroutine.prof")
	}()

	// 程序将一直运行，直到被手动终止
	select {}
}

// 使用方法:
// 1. 运行程序: go run goroutine_example.go
// 2. 访问 http://localhost:7890/debug/pprof/goroutine 查看Goroutine信息
// 3. 使用命令行分析: go tool pprof http://localhost:7890/debug/pprof/goroutine
// 4. 或者分析生成的文件: go tool pprof goroutine.prof
// 5. 在pprof交互式命令行中输入: top, web, list等命令
